home *** CD-ROM | disk | FTP | other *** search
/ Macwelt 1 / Macwelt DVD 1.toast / Web-Publishing / HTML-Editoren / Alpha ƒ / Tcl / Modes / lispMode.tcl < prev    next >
Encoding:
Text File  |  2001-01-15  |  59.7 KB  |  1,708 lines

  1. ## -*-Tcl-*-  (nowrap)
  2.  # ==========================================================================
  3.  #  Lisp Mode - an extension package for Alpha
  4.  # 
  5.  #  FILE: "lispMode.tcl"  
  6.  #                                    created: 02/07/00 {12:32:35 pm} 
  7.  #                                last update: 01/15/2001 {22:38:12 PM} 
  8.  #  Description: 
  9.  # 
  10.  #  For deciphering Lisp files.
  11.  #  
  12.  #  The Scm mode could also be used for reading .el files -- Scheme is a
  13.  #  variant of Lisp.  I didn't realize this until I was constructing the Mode
  14.  #  Examples Help file.  Perhaps the two could be combined someday.
  15.  #  
  16.  #  Author: Craig Barton Upright
  17.  #  E-mail: <cupright@princeton.edu>
  18.  #    mail: Princeton University,  Department of Sociology
  19.  #          Princeton, New Jersey  08544
  20.  #     www: <http://www.princeton.edu/~cupright>
  21.  #  
  22.  # -------------------------------------------------------------------
  23.  #  
  24.  # Copyright (c) 2000  Craig Barton Upright
  25.  # 
  26.  # This program is free software; you can redistribute it and/or modify
  27.  # it under the terms of the GNU General Public License as published by
  28.  # the Free Software Foundation; either version 2 of the License, or
  29.  # (at your option) any later version.
  30.  # 
  31.  # This program is distributed in the hope that it will be useful,
  32.  # but WITHOUT ANY WARRANTY; without even the implied warranty of
  33.  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  34.  # GNU General Public License for more details.
  35.  # 
  36.  # You should have received a copy of the GNU General Public License
  37.  # along with this program; if not, write to the Free Software
  38.  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  39.  # 
  40.  # ==========================================================================
  41.  ##
  42.  
  43. # ===========================================================================
  44. #
  45. # ◊◊◊◊ Initialization of Lisp mode ◊◊◊◊ #
  46.  
  47. alpha::mode Lisp 2.0 lispMenu {*.el *.elc *.lisp *.lsp} {
  48.     lispMenu electricReturn electricTab electricBraces 
  49. } {
  50.     # We require 7.4b21 for prefs handling.
  51.     alpha::package require AlphaTcl 7.4b21
  52.     addMenu lispMenu "Lisp" Lisp
  53.     set modeCreator(ROSA) {Lisp}
  54. } uninstall {
  55.     catch {file delete [file join $HOME Tcl Modes lispMode.tcl]}
  56.     catch {file delete [file join $HOME Tcl Completions LispCompletions.tcl]}
  57.     catch {file delete [file join $HOME Tcl Completions "Lisp Tutorial.el"]}
  58.     catch {file delete [file join $HOME Help "Lisp Help"]}
  59. } help {
  60.     file "Lisp Help"
  61. } maintainer {
  62.     "Craig Barton Upright" <cupright@princeton.edu> 
  63.     <http://www.princeton.edu/~cupright/>
  64. }
  65.  
  66. proc lispMode.tcl {} {}
  67.  
  68. namespace eval Lisp {}
  69.  
  70. # Make sure that Scheme mode gets loaded before the menu.
  71. if {[catch {schemeMode.tcl}]} {
  72.     alertnote "The file \"schemeMode.tcl\" did not load properly.\
  73.       Perhaps it needs to be re-installed?"
  74.  
  75.  
  76. # ===========================================================================
  77. #
  78. # ◊◊◊◊ Setting Lisp mode variables ◊◊◊◊ #
  79. #
  80.  
  81. # Removing obsolete preferences from earlier versions.
  82.  
  83. set oldvars {
  84.     addLispCommands don'tRemindMe electricTab functionColor keywordColor
  85. }
  86.  
  87. foreach oldvar $oldvars {prefs::removeObsolete LispmodeVars($oldvar)}
  88.  
  89. unset oldvars
  90.  
  91. #=============================================================================
  92. #
  93. # Standard preferences recognized by various Alpha procs
  94. #
  95.  
  96. newPref var  fillColumn        {75}            Lisp
  97. newPref var  indentationAmount {4}             Lisp
  98. newPref var  leftFillColumn    {0}             Lisp
  99. newPref var  prefixString      {;; }           Lisp
  100. newPref var  wordBreak         {[\w\-]+}       Lisp
  101. newPref var  wordBreakPreface  {([^\w\-])}     Lisp
  102. newPref flag wordWrap          {0}             Lisp
  103.  
  104.  
  105. #=============================================================================
  106. #
  107. # Flag preferences
  108. #
  109.  
  110. # Indent all continued commands, indicated by unmatched parantheses, by the
  111. # full indentation amount rather than half.
  112. newPref flag fullIndent        {1}             Lisp
  113.  
  114. newPref flag autoMark          {0}             Lisp
  115.  
  116. # Set the list of flag preferences which can be changed in the menu.
  117.  
  118. set LispPrefsInMenu [list   \
  119.   "fullIndentLisp"          \
  120.   "fullIndentScm"           \
  121.   ]
  122.  
  123. #=============================================================================
  124. #
  125. # Variable preferences
  126.  
  127. # Enter additional arguments to be colorized.
  128. newPref var addArguments      {}              Lisp    {Lisp::colorizeLisp}
  129.  
  130. # Enter additional Lisp commands to be colorized.  
  131. newPref var addCommands       {}              Lisp    {Lisp::colorizeLisp}
  132.  
  133. # Command double-clicking on a Lisp keyword will send it to this url
  134. # for a help reference page.
  135. newPref url lispHelp {http://www.harlequin.com:8000/xanalys_int/query.html?qt=} Lisp
  136.  
  137. # The "Lisp Home Page" menu item will send this url to your browser.
  138. newPref url lispHomePage      {http://www.lisp.org/}      Lisp
  139.  
  140. # Click on "Set" to find the local Stata application.
  141. newPref sig lispSig          {ROSA}          Lisp
  142.  
  143. # ===========================================================================
  144. # Color preferences
  145. #
  146.  
  147. newPref color argumentColor     {magenta}       Lisp    {Lisp::colorizeLisp}
  148. newPref color commandColor      {blue}          Lisp    {Lisp::colorizeLisp}
  149. newPref color commentColor      {red}           Lisp    {stringColorProc}
  150. newPref color stringColor       {green}         Lisp    {stringColorProc}
  151. newPref color symbolColor       {magenta}       Lisp    {Lisp::colorizeLisp}
  152.  
  153. regModeKeywords -e {;}                      \
  154.       -c $LispmodeVars(commentColor)        \
  155.       -s $LispmodeVars(stringColor) Lisp {}
  156.  
  157. # ==========================================================================
  158. # Comment Character variables for Comment Line / Paragraph / Box menu items.
  159.  
  160. set Lisp::commentCharacters(General)    ";; "
  161. set Lisp::commentCharacters(Paragraph)  [list ";; " " ;;" " ; "]
  162. set Lisp::commentCharacters(Box)        [list ";" 2 ";" 2 ";" 3]
  163.  
  164. # ===========================================================================
  165. # Flag Flip
  166. # Called by menu items, change the value of flag preferences.
  167.  
  168. proc Lisp::flagFlip {pref} {
  169.     
  170.     global mode
  171.     
  172.     set trueMode $mode
  173.     set end2 "."
  174.     if {[regexp {^([a-zA-Z0-9]+[a-zA-Z0-9])(Scm|Lisp)} $pref match pref prefMode]} {
  175.         set mode $prefMode
  176.         set end2 " for $prefMode mode."
  177.     } else {
  178.         Lisp::LispModeMenuItem 1 1
  179.     } 
  180.     if {$mode == "Lisp"} {
  181.         global LispmodeVars
  182.         set LispmodeVars($pref) [expr {$LispmodeVars($pref) ? 0 : 1}]
  183.         synchroniseModeVar $pref $LispmodeVars($pref)
  184.         if {$LispmodeVars($pref)} {
  185.             set end1 "on"
  186.         } else {
  187.             set end1 "off"        
  188.         } 
  189.     } elseif {$mode == "Scm"} {
  190.         global ScmmodeVars
  191.         set ScmmodeVars($pref) [expr {$ScmmodeVars($pref) ? 0 : 1}]
  192.         synchroniseModeVar $pref $ScmmodeVars($pref)
  193.         if {$ScmmodeVars($pref)} {
  194.             set end1 "on"
  195.         } else {
  196.             set end1 "off"        
  197.         } 
  198.     } 
  199.     set mode $trueMode
  200.     message "The \"$pref\" preference is now $end1$end2"
  201. }
  202.  
  203. # ===========================================================================
  204. #
  205. # ◊◊◊◊ Keyword Dictionaries ◊◊◊◊ #
  206. #
  207.  
  208. # Making sure that LispUserCommands and LispUserArguments exist.
  209. # These will be over-ridden if they are loaded from a ${mode}Prefs.tcl file.
  210. #
  211.  
  212. set LispUserCommands    ""
  213. set LispUserArguments   ""
  214.  
  215. # ===========================================================================
  216. #
  217. # ◊◊◊◊   Lisp Accessors   ◊◊◊◊ #
  218. #
  219.  
  220. set LispAccessors {
  221.     bit car cdr caar cadr cdar cddr caaar caadr cadar caddr cdaar cdadr
  222.     cddar cdddr caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr
  223.     cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr char
  224.     compiler-macro-function eighth fifth first fourth ninth sbit schar
  225.     second seventh sixth tenth third aref elt fdefinition fill-pointer
  226.     find-class get getf gethash ldb logical-pathname-translations
  227.     macro-function mask-field nth readtable-case rest row-major-aref subseq
  228.     svref symbol-function symbol-plist symbol-value values
  229.  
  230. }
  231.  
  232. # ===========================================================================
  233. #
  234. # ◊◊◊◊   Lisp Classes   ◊◊◊◊ #
  235. #
  236.  
  237. set LispClasses {
  238.     standard-object structure-object
  239.  
  240. # ===========================================================================
  241. #
  242. # ◊◊◊◊   Lisp Condition Types   ◊◊◊◊ #
  243. #
  244.  
  245. set LispConditionTypes {
  246.     cell-error condition control-error division-by-zero end-of-file error
  247.     file-error floating-point-invalid-operation floating-point-overflow
  248.     floating-point-underflow floating-point-inexact package-error
  249.     parse-error print-not-readable program-error reader-error
  250.     serious-condition simple-condition simple-error simple-type-error
  251.     simple-warning storage-condition stream-error style-warning type-error
  252.     unbound-slot unbound-variable undefined-function warning
  253.  
  254. # ===========================================================================
  255. #
  256. # ◊◊◊◊   Lisp Constant Variables   ◊◊◊◊ #
  257. #
  258.  
  259. set LispConstantVariables {
  260.     array-dimension-limit array-rank-limit array-total-size-limit boole-1
  261.     boole-2 boole-and boole-andc1 boole-andc2 boole-c1 boole-c2 boole-clr
  262.     boole-eqv boole-ior boole-nand boole-nor boole-orc1 boole-orc2
  263.     boole-set boole-xor call-arguments-limit char-code-limit
  264.     double-float-epsilon double-float-negative-epsilon
  265.     internal-time-units-per-second lambda-list-keywords
  266.     lambda-parameters-limit least-negative-double-float
  267.     least-negative-long-float least-negative-normalized-double-float
  268.     least-negative-normalized-long-float
  269.     least-negative-normalized-short-float
  270.     least-negative-normalized-single-float least-negative-short-float
  271.     least-negative-single-float least-positive-double-float
  272.     least-positive-long-float least-positive-normalized-double-float
  273.     least-positive-normalized-long-float
  274.     least-positive-normalized-short-float
  275.     least-positive-normalized-single-float least-positive-short-float
  276.     least-positive-single-float long-float-epsilon
  277.     long-float-negative-epsilon t most-negative-double-float
  278.     most-negative-fixnum most-negative-long-float most-negative-short-float
  279.     most-negative-single-float most-positive-double-float
  280.     most-positive-fixnum most-positive-long-float most-positive-short-float
  281.     most-positive-single-float multiple-values-limit nil pi
  282.     short-float-epsilon short-float-negative-epsilon single-float-epsilon
  283.     single-float-negative-epsilon
  284.  
  285. # ===========================================================================
  286. #
  287. # ◊◊◊◊   Lisp Declarations   ◊◊◊◊ #
  288. #
  289.  
  290. set LispDeclarations {
  291.     declaration dynamic-extent ftype ignore, ignorable inline notinline
  292.     optimize special
  293.  
  294. # ===========================================================================
  295. #
  296. # ◊◊◊◊   Lisp Functions   ◊◊◊◊ #
  297. #
  298.  
  299. set LispFunctions {
  300.     - 1 1+ 1- abort abs acons acos adjoin adjust-array adjustable-array-p
  301.     alpha-char-p alphanumericp append apply apropos apropos-list arithmeti
  302.     array-dimension array-dimensions array-displacement array-element-type
  303.     array-has array-in-bounds-p array-rank array-row-major-index
  304.     array-total-size arrayp ash asin assoc assoc-if-not at-arguments atan
  305.     atanh bit-and bit-andc1 bit-andc2 bit-eqv bit-ior bit-nand bit-nor
  306.     bit-not bit-orc1 bit-orc2 bit-vector-p bit-xor boole both-case-p boundp
  307.     break broadcast butlast byte byte-position byte-size cal-pathname
  308.     ceiling cell-error-name cerror char char-code char-downcase char-equal
  309.     char-greaterp char-int char-lessp char-name char-not-equal
  310.     char-not-greaterp char-not-lessp char-upcase character characterp cis
  311.     class-of clear-input clear-output close clrhash code-char coerce
  312.     compile compile-file compile-file-pathname compiled-function-p
  313.     complement complex complexp compute-restarts concatenate conjugate cons
  314.     consp constantly constantp continue copy-alist copy-list
  315.     copy-pprint-dispatch copy-readtable copy-seq copy-structure copy-symbol
  316.     copy-tree cos cosH count count-if count-if-not dable-object decode-fl
  317.     decode-float decode-universal-time decoded-time delete
  318.     delete-duplicates delete-file delete-if delete-if-not delete-package
  319.     denominator deposit-field describe digit-char digit-char-p directory
  320.     directory-namestring disassemble dpb dribble echo-stream-input-stream
  321.     echo-stream => input-stream echo-stream-output-stream echo-stream
  322.     output-stream ed encode-universal-time endp enough-namestring ensure-di
  323.     ensure-ge eq eql equal equalp error eval evenp every exp export expt
  324.     fboundp fceiling ffloor file-author file-error-pathname file-length
  325.     file-namestring file-position file-string-length file-write-date fill
  326.     find find-all-symbols find-if find-if-not find-package find-restart
  327.     find-symbol finish-output float floatp floor fmakunbound force-output
  328.     format fresh-line fround fround ftruncate funcall
  329.     function-lambda-expression functionp gcd gensym gentemp
  330.     get-dispatch-macro-character get-internal-real-time
  331.     get-internal-run-time get-macro-character get-outpu get-properties
  332.     get-setf-expansion get-unive graphic-char-p hash-table-count
  333.     hash-table-p hash-table-rehash-size hash-table-rehash-threshold
  334.     hash-table-size hash-table-test host-namestring identity imagpart
  335.     import input-stream-p inspect integer-length integerp
  336.     interactive-stream-p intern intersect intersection invalid-method-error
  337.     invoke-debugger invoke-re invoke-restart isqrt keywordp last lcm
  338.     ldb-test ldiff length lisp-implementation-type
  339.     lisp-implementation-version list list-all-packages list-length listen
  340.     listp listst ll-pointer-p load load-logi log logand logandc1 logandc2
  341.     logbitp logcount logeqv logical-pathname logior lognand lognor lognot
  342.     logorc1 logorc2 logtest logxor long-site-name lower-case-p
  343.     machine-instance machine-type machine-version macroexpand macroexpand-1
  344.     make-array make-broadcast-stream make-concatenated-stream
  345.     make-condition make-dispatch-macro-character make-echo-stream
  346.     make-hash-table make-list make-load-form-saving-slots make-package
  347.     make-pathname make-random-state make-sequence make-string
  348.     make-string-input-stream make-symbol make-synonym-stream
  349.     make-two-way-stream makunbound map map-into mapc mapcan mapcar mapcon
  350.     mapcon maphash mapl maplist max member member-if member-if-not merge
  351.     merge-pathnames method-combination-error min minusp mismatch mod
  352.     muffle-warning name-char name-version namestring nbutlast nconc not
  353.     notany notevery nreconc nreverse nset-difference nset-exclusive-or
  354.     nstring-capitalize nstring-downcase nstring-upcase nsublis nsubst
  355.     nsubst-if nsubst-if-not nteractively nthcdr null numberp numerator
  356.     nunion oddp open open-stream-p or-operation output-stream-p
  357.     package-error-package package-name package-nicknames package-s
  358.     package-use-list package-used-by-list packagep pairlis parse-integer
  359.     parse-namestring pathname pathname- pathname-match-p pathnamep
  360.     peek-char phase pl plusp position position-if position-if-not pprint
  361.     pprint-dispatch pprint-fill pprint-indent pprint-linear pprint-newline
  362.     pprint-tab pprint-tabular prin1 prin1-to-string princ princ-to-string
  363.     print print-not probe-file proclaim provide random random-state-p
  364.     rassoc rassoc-if rassoc-if-not rational rationalize rationalp read
  365.     read-byte read-char read-char-no-hang read-delimited-list
  366.     read-from-string read-line read-preserving-whitespace read-sequence
  367.     readtablep realp realpart ream-streams ream-streams reduce rem remhash
  368.     remove remove-duplicates remove-if remove-if-not remprop rename-file
  369.     rename-package replace require restart-name revappend reverse
  370.     ric-function room round rplaca rplacd search set set-difference
  371.     set-dispatch-macro-character set-exclusive-or set-macro-character
  372.     set-pprint-dispatch set-syntax-from-char shadow shadowing-import
  373.     short-site-name signal signum simple-bit-vector-p
  374.     simple-condition-format-control simple-condition-format-arguments
  375.     simple-string-p simple-vector-p sin sinh sl sleep slot-boundp
  376.     slot-exists-p slot-makunbound slot-value software-type software-version
  377.     some sort special-operator-p sqrt st stable-sort standard-char-p
  378.     store-value stream-element-type stream-error-stream
  379.     stream-external-format streamp string string string-capitalize
  380.     string-downcase string-equal string-greaterp string-left-trim
  381.     string-lessp string-not-equal string-not-greaterp string-not-lessp
  382.     string-right-trim string-trim string-upcase stringeqc stringp sublis
  383.     subsetp subst subst-if subst-if-not subst-if-not substitute subtypep
  384.     sxhash symbol-name symbol-package symbolp synonym-stream-symbol tailp
  385.     tan terpri tories-exist translate translate-pathname translations
  386.     tream-string tree-equal truename truncate two-way-stream-input-stream
  387.     two-way-stream-output-stream type-error-datum type-error-expected-type
  388.     type-of typep unbound-slot-instance unexport unintern union unread-char
  389.     unuse-package upgraded-array-element-type upgraded-complex-part-type
  390.     upper-case-p use-package use-value user-homedir-pathname values-list
  391.     vector vector-pop vector-push vector-push-extend vectorp warn
  392.     wild-pathname-p wing-symbols write write-byte write-char write-line
  393.     write-sequence write-string write-to-string y-or-n-p yes-or-no-p zerop
  394. }
  395.  
  396. # ===========================================================================
  397. #
  398. # ◊◊◊◊   Lisp Macros   ◊◊◊◊ #
  399. #
  400.  
  401. set LispMacros {
  402.     and assert case ccase check-type cond decf declaim defclass defconstant
  403.     defgeneric define-compiler-macro define-condition
  404.     define-method-combination define-setf-expander define-symbol-macro
  405.     defmacro defmethod defpackage defparameter defsetf defstruct deftype
  406.     defun defvar destructuring-bind do do-all-symbols do-external-symbols
  407.     do-symbols dolist dotimes ecase etypecase formatter handler-bind
  408.     handler-case ignore-errors in-package incf lambda loop
  409.     multiple-value-bind multiple-value-list multiple-value-setq nth-value
  410.     or pop pprint-logical-block print-unreadable-object prog prog1 prog2
  411.     progst psetf psetq push pushnew remf restart-bind restart-case return
  412.     rotatef setf shiftf step time trace typecase unless untrace when
  413.     with-accessors with-compilation-unit with-condition-restarts
  414.     with-hash-table-iterator with-input-from-string with-open-file
  415.     with-open-stream with-output-to-string with-package-iterator
  416.     with-simple-restart with-slots with-standard-io-syntax
  417.  
  418. }
  419.  
  420. # ===========================================================================
  421. #
  422. # ◊◊◊◊   Lisp Restarts   ◊◊◊◊ #
  423. #
  424.  
  425. set LispRestarts {
  426.     abort continue muffle-warning
  427.  
  428. # ===========================================================================
  429. #
  430. # ◊◊◊◊   Lisp Specials   ◊◊◊◊ #
  431. #
  432.  
  433. set LispSpecials {
  434.     flet labels macrolet multiple-value-prog1 block catch eval-when
  435.     function go if let load-time-value locally multiple-value-call progn
  436.     progv quote return-from setq symbol-macrolet tagbody the throw
  437.     unwind-protect
  438. }
  439.  
  440. # ===========================================================================
  441. #
  442. # ◊◊◊◊   Lisp Standard Generic Functions   ◊◊◊◊ #
  443. #
  444.  
  445. set LispStandardGenericFunctions {
  446.     add-method allocate-instance change-class class-name
  447.     compute-applicable-methods describe-object documentation find-method
  448.     function-keywords initialize-instance make-instances-obsolete
  449.     make-instance make-load-form method-qualifiers no-applicable-method
  450.     no-next-method class-name print-object reinitialize-instance
  451.     remove-method shared-initialize slot-missing slot-unbound
  452.     update-instance-for-redefined-class update-instance-for-different-class
  453.  
  454. # ===========================================================================
  455. #
  456. # ◊◊◊◊   Lisp Symbols   ◊◊◊◊ #
  457. #
  458.  
  459. set LispSymbols {
  460.     declare lambda
  461.  
  462.  
  463. # ===========================================================================
  464. #
  465. # ◊◊◊◊   Lisp System Classes   ◊◊◊◊ #
  466. #
  467.  
  468. set LispSystemClasses {
  469.     array bit-vector broadcast-stream built-in-class character class
  470.     complex concatenated-stream cons echo-stream file-stream float function
  471.     generic-function hash-table integer list logical-pathname
  472.     method-combination method null number package pathname random-state
  473.     ratio rational readtable real restart sequence
  474.     standard-generic-function standard-class standard-method stream
  475.     string-stream string structure-class symbol synonym-stream t
  476.     two-way-stream vector
  477.  
  478. # ===========================================================================
  479. #
  480. # ◊◊◊◊   Lisp Types   ◊◊◊◊ #
  481. #
  482.  
  483. set LispTypes {
  484.     atom base-char base-string bignum bit boolean compiled-function
  485.     extended-char fixnum keyword nil short-float single-float double-float
  486.     long-float signed-byte simple-array simple-base-string
  487.     simple-bit-vector simple-string simple-vector standard-char
  488.     unsigned-byte
  489.  
  490. # ===========================================================================
  491. #
  492. # ◊◊◊◊   Lisp Type Specifiers   ◊◊◊◊ #
  493. #
  494.  
  495. set LispTypeSpecifiers {
  496.     and eql member mod not or satisfies values
  497.  
  498. # ===========================================================================
  499. #
  500. # ◊◊◊◊   Lisp Variables   ◊◊◊◊ #
  501. #
  502.  
  503. set LispVariables {
  504.     *break-on-signals* *compile-file-pathname* *compile-file-truename*
  505.     *compile-print* *compile-verbose* *debug-io* *error-output* *query-io*
  506.     *standard-input* *standard-output* *trace-output* *debugger-hook*
  507.     *default-pathname-defaults* *features* *gensym-counter* *load-pathname*
  508.     *load-truename* *load-print* *load-verbose* *macroexpand-hook*
  509.     *modules* *package* *print-array* *print-base* *print-radix*
  510.     *print-case* *print-circle* *print-escape* *print-gensym* *print-level*
  511.     *print-length* *print-lines* *print-miser-width*
  512.     *print-pprint-dispatch* *print-pretty* *print-readably*
  513.     *print-right-margin* random-statest *read-base*
  514.     *read-default-float-format* *read-eval* *read-suppress* *readtable*
  515.     *terminal-io*
  516.  
  517. # ===========================================================================
  518. #
  519. # ◊◊◊◊   Lisp Emacs Functions   ◊◊◊◊ #
  520. # ??
  521.  
  522. set LispEmacsFunctions {
  523.     autoload beep cs defalias defconst defcustom defdir defgroup defsubst
  524.     ding force fset insert interactive mapconcat memq message prompt put
  525.     setcar switch vconcat while
  526. }
  527.  
  528. # ===========================================================================
  529. #
  530. # ◊◊◊◊   Lisp Emacs Arguments   ◊◊◊◊ #
  531. # ??
  532.  
  533. set LispEmacsArguments {
  534.     dirname fbuffer fname insertpos key nil node nodocs nomessage olist
  535.     position switches t tbuffer
  536.  
  537. # ===========================================================================
  538. # Colorize Lisp.
  539. # Used to update preferences, and could be called in a <mode>Prefs.tcl file
  540.  
  541. proc Lisp::colorizeLisp {{pref ""}} {
  542.     
  543.     global LispmodeVars LispAccessors LispClasses LispConditionTypes 
  544.     global LispConstantVariables LispDeclarations LispFunctions LispMacros 
  545.     global LispRestarts LispSpecials LispStandardGenericFunctions LispSymbols
  546.     global LispSystemClasses LispTypes LispTypeSpecifiers LispVariables
  547.     global LispEmacsFunctions LispEmacsArguments 
  548.     global LispUserCommands LispUserArguments
  549.     
  550.     global LispCommandList Lispcmds
  551.     
  552.     # First setting aside only the commands, for Lisp::Completion::Command.
  553.     set LispCommandList [concat \
  554.       $LispAccessors $LispClasses $LispConditionTypes \
  555.       $LispConstantVariables $LispDeclarations $LispFunctions \
  556.       $LispMacros $LispSpecials $LispStandardGenericFunctions \
  557.       $LispSymbols $LispSystemClasses $LispTypes $LispTypeSpecifiers \
  558.       $LispVariables \
  559.       $LispEmacsFunctions \
  560.       $LispmodeVars(addCommands) $LispUserCommands \
  561.       ]
  562.     
  563.     # Then, create the list of all keywords for completions.
  564.     set Lispcmds [lsort [lunique [concat \
  565.       $LispCommandList \
  566.       $LispEmacsArguments \
  567.       $LispmodeVars(addArguments) $LispUserArguments \
  568.       ]]]
  569.     # Commmands
  570.      regModeKeywords -a -k $LispmodeVars(commandColor) \
  571.        Lisp $LispCommandList 
  572.      
  573.      # Arguments
  574.      set LispArgumentColorList [concat                                   \
  575.        $LispEmacsArguments                                               \
  576.        $LispmodeVars(addArguments) $LispUserArguments]
  577.      regModeKeywords -a                                                  \
  578.        -k $LispmodeVars(argumentColor) Lisp $LispArgumentColorList
  579.      
  580.      # Symbols
  581.      regModeKeywords -a                                                  \
  582.        -k $LispmodeVars(symbolColor) Lisp {}                             \
  583.        -i "+" -i "-" -i "*" -i "_" -i "\\" "/"                           \
  584.        -I $LispmodeVars(symbolColor)
  585.     if {$pref != ""} {refresh}
  586. }
  587.  
  588. # Call this now.
  589.  
  590. Lisp::colorizeLisp
  591.  
  592. # ===========================================================================
  593. #
  594. # Reload Completions.  
  595. # This is now an obsolete proc.
  596.  
  597. proc Lisp::reloadCompletions {} {
  598.     alertnote "\"Lisp::reloadCompletions\" is an obsolete proc.\
  599.       It should be removed from your LispPrefs.tcl file."
  600. }
  601.  
  602. # ===========================================================================
  603. #
  604. # ◊◊◊◊ Key Bindings, Electrics ◊◊◊◊ #
  605. # abbreviations:  <o> = option, <z> = control, <s> = shift, <c> = command
  606.  
  607. # Known bug: Key-bindings from other global menus might conflict with those
  608. # defined in the Lisp menu.  This will help ensure that this doesn't happen.
  609.  
  610. Bind 's'    <cs>    {Lisp::switchToLisp} Lisp
  611. Bind 'p'    <cs>    {Lisp::processFile} Lisp
  612. Bind 'p'    <csz>   {Lisp::processSelection} Lisp
  613.  
  614. Bind 'n'    <sz>    {Lisp::nextCommand} Lisp
  615. Bind 'p'    <sz>    {Lisp::prevCommand} Lisp
  616. Bind 's'    <sz>    {Lisp::selectCommand} Lisp
  617. Bind 'c'    <sz>    {Lisp::copyCommand} Lisp
  618.  
  619. Bind 'i'    <cz>    {Lisp::reformatCommand} Lisp
  620.  
  621. Bind '\r'   <z>     {typeText "\r" }  Lisp
  622. Bind '\r'   <s>     {Lisp::continueCommand} Lisp
  623. Bind '\)'           {Lisp::electricRight "\)"} Lisp
  624.  
  625. # For those that would rather use arrow keys to navigate.  Up and down
  626. # arrow keys will advance to next/prev command, right and left will also
  627. # set the cursor to the top of the window.
  628.  
  629. Bind    up  <sz>    {Lisp::prevCommand} Lisp
  630. Bind  left  <sz>    {Lisp::prevCommand 0 1} Lisp
  631. Bind  down  <sz>    {Lisp::nextCommand} Lisp
  632. Bind right  <sz>    {Lisp::nextCommand 0 1} Lisp
  633.  
  634. # ===========================================================================
  635. # Lisp Carriage Return
  636. # Inserts a carriage return, and indents properly.
  637.  
  638. proc Lisp::carriageReturn {} {
  639.     
  640.     global LispmodeVars
  641.     
  642.     if {[isSelection]} {
  643.         deleteSelection
  644.     } 
  645.     set pos1 [lineStart [getPos]]
  646.     set pos2 [getPos]
  647.     if {[regexp {^([\t ])*\)} [getText $pos1 $pos2]]} {
  648.         createTMark temp $pos2
  649.         Lisp::indentLine
  650.         gotoTMark temp ; removeTMark temp
  651.     } 
  652.     insertText "\r"
  653.     bind::IndentLine
  654. }
  655.  
  656. proc Lisp::electricRight {{char "\}"}} {
  657.     
  658.     set pos [getPos]
  659.     typeText $char
  660.     if {![regexp {[^ \t]} [getText [lineStart $pos] $pos]]} {
  661.         set pos [lineStart $pos]
  662.         createTMark temp [getPos]
  663.         Lisp::indentLine
  664.         gotoTMark temp ; removeTMark temp
  665.         bind::CarriageReturn
  666.     } 
  667.     if {[catch {blink [matchIt $char [pos::math $pos - 1]]}]} {
  668.         beep ; message "No matching $char !!"
  669.     } 
  670. }
  671.  
  672. # ===========================================================================
  673. #
  674. # Continue Command
  675. # Over-rides the automatic indentation of lines that begin with \) so that
  676. # additional text can be entered.
  677.  
  678. proc Lisp::continueCommand {} {
  679.     
  680.     global mode LispmodeVars ScmmodeVars indent_amounts
  681.     
  682.     Lisp::LispModeMenuItem
  683.     
  684.     Lisp::carriageReturn
  685.     if {[pos::compare [getPos] != [maxPos]]} {
  686.         set nextChar [getText [getPos] [pos::math [getPos] + 1]]
  687.         if {$nextChar == "\)"} {
  688.             if {$mode == "Lisp"} {
  689.                 set continueIndent [expr {$LispmodeVars(fullIndent) + 1}]
  690.             } elseif {$mode == "Scm"} {
  691.                 set continueIndent [expr {$ScmmodeVars(fullIndent) + 1}]
  692.             } 
  693.             insertText [text::indentOf $indent_amounts($continueIndent)]
  694.         } 
  695.     } 
  696. }
  697.  
  698. # ===========================================================================
  699. #
  700. # ◊◊◊◊ Indentation ◊◊◊◊ #
  701. # Lisp::correctIndentation is necessary for Smart Paste, and returns the
  702. # correct level of indentation for the current line.  Lisp::indentLine uses
  703. # this level to indent the current line.
  704. # Adapted from schemeMode.tcl, which includes this rationale:
  705. # -------- 
  706. # Computing the balance of parentheses within the 'line'.
  707. # This appears to be utterly elementary.  One has to keep in mind however
  708. # that parentheses might appear in comments and/or quoted strings, in which
  709. # case they shouldn't count.  Although it's easy to detect a Scheme comment
  710. # by a semicolon, a semicolon can also appear within a quoted string.  Note
  711. # that a double quote isn't that sure a sign of a quoted string: the double
  712. # quote may be escaped.  And the backslash can be escaped in turn...  Thus
  713. # we face a full-blown problem of parsing a string according to a
  714. # context-free grammar.  We note however that a TCL interpretor does
  715. # similar kind of parsing all the time.  So, we can piggy-back on it and
  716. # have it decide what is the quoted string and when a semicolon really
  717. # starts a comment.  To this end, we replace all non-essential characters
  718. # from the 'line' with spaces, separate all parens with spaces (so each
  719. # paren would register as a separate token with the TCL interpretor),
  720. # replace a semicolon with an opening brace (which, if unescaped and
  721. # unquoted, acts as some kind of "comment", that is, shields all symbols
  722. # that follows).  After that, we get TCL interpretor to convert thus
  723. # prepared 'line' into a list, and simply count the balance of '(' and ')'
  724. # tokens.
  725. # -------- 
  726. # Given that initial plan, I have adapted it to simply remove anything
  727. # surrounded by double quotes (taking pains to still honor literal
  728. # characters), remove valid comments, and convert the remaining parans into
  729. # "more" and "less".  No need to piggy-back on the Tcl interpreter anymore.
  730. # -- cbu
  731.  
  732. proc Lisp::indentLine {{pos ""}} {
  733.     
  734.     if {$pos == ""} {set pos [getPos]} 
  735.     # Get details of current line.
  736.     set posBeg [lineStart [getPos]]
  737.     set text [getText $posBeg [nextLineStart $posBeg]]
  738.     regexp {^[ \t]*} $text white 
  739.     set posNext1 [pos::math $posBeg + [string length $white]]
  740.     set posNext2 [pos::math $posNext1 + 1]
  741.     if {[pos::compare $posNext2 > [maxPos]]} {
  742.         set posNext2 [maxPos]
  743.     } 
  744.     # Determine the correct level of indentation for this line, given the
  745.     # next character.
  746.     set lwhite [Lisp::correctIndentation $pos [getText $posNext1 $posNext2]]
  747.     set lwhite [text::indentOf $lwhite]
  748.     if {$white != $lwhite} {
  749.         replaceText $posBeg $posNext1 $lwhite
  750.     }
  751.     goto [pos::math $posBeg + [string length $lwhite]]
  752. }
  753.  
  754. proc Lisp::correctIndentation {pos {next ""}} {
  755.     
  756.     global mode indent_amounts LispmodeVars ScmmodeVars
  757.     
  758.     if {$mode == "Lisp"} {
  759.         set continueIndent [expr {$LispmodeVars(fullIndent) + 1}]
  760.     } elseif {$mode == "Scm"} {
  761.         set continueIndent [expr {$ScmmodeVars(fullIndent)  + 1}]
  762.     } else {
  763.         set continueIndent ${indent_amounts(1)}
  764.     } 
  765.     
  766.     set posBeg   [lineStart $pos]
  767.     # Get information about this line, previous line ...
  768.     set thisLine [Lisp::getCommandLine $posBeg 1 1]
  769.     set prevLine [Lisp::getCommandLine [pos::math $posBeg - 1] 0 1]
  770.     set lwhite   [lindex $prevLine 1]
  771.     # If we have a previous line ...
  772.     if {[pos::compare [lindex $prevLine 0] != $posBeg]} {
  773.         # Find out if there are any unbalanced (,) in the last line.
  774.         regsub -all {[^ \(\)\"\;\\]} $prevLine { } line
  775.         # Remove all literals.
  776.         regsub -all {\\\(|\\\)|\\\"|\\\;} $line { } line
  777.         regsub -all {\\} $line { } line
  778.         # If there is only one quote in a line, next to a closing brace,
  779.         # assume that this is a continued quote from another line.  So add
  780.         # a double quote at the beginning of the line (which will make us
  781.         # ignore everything up to that point).  Not entirely foolproof ...
  782.         if {![regexp {\"+.+\"} $line] && [regexp {\"([\t ]?)\)} $line]} {
  783.             set line [concat \"$line]
  784.         } 
  785.         # Remove everything surrounded by quotes.
  786.         regsub -all {\"([^\"]+)\"} $line { } line
  787.         regsub -all {\"} $line { } line
  788.         # Remove all characters following the first valid comment.
  789.         if {[regexp {\;} $line]} {
  790.             set line [string range $line 0 [string first {;} $line]]
  791.         } 
  792.         # Now turn all braces into "more" and "less"
  793.         regsub -all {\(} $line { more } line
  794.         regsub -all {\)} $line { less } line
  795.         # Now indent based upon more and less.
  796.         foreach i $line {
  797.             if {$i == "more"} {
  798.                 incr lwhite $indent_amounts($continueIndent)
  799.             } elseif {$i == "less"} {
  800.                 incr lwhite $indent_amounts(-$continueIndent)
  801.             }
  802.         }
  803.         # Did the last line start with a lone \) ?  If so, we want to keep the
  804.         # indent, and not make call it an unbalanced line.
  805.         if {[regexp {^[\t ]*\)} [lindex $prevLine 2]]} {
  806.             incr lwhite $indent_amounts($continueIndent)
  807.         } 
  808.     }
  809.     # If we have a current line ...
  810.     if {[pos::compare [lindex $thisLine 0] == $posBeg]} {
  811.         # Reduce the indent if the first non-whitespace character of this
  812.         # line is ) or \}.
  813.         if {$next == ")" || [regexp {^[\t ]?\)} [lindex $thisLine 2]]} {
  814.             incr lwhite $indent_amounts(-$continueIndent)
  815.         } 
  816.     }
  817.     # Now we return the level to the calling proc.
  818.     return [expr {$lwhite > 0 ? $lwhite : 0}]
  819. }
  820.  
  821. # ===========================================================================
  822. # Get Command Line
  823. # Find the next/prev command line relative to a given position, and return
  824. # the position in which it starts, its indentation, and the complete text
  825. # of the command line.  If the search for the next/prev command fails,
  826. # return an indentation level of 0.
  827.  
  828. proc Lisp::getCommandLine {pos {direction 1} {ignoreComments 1}} {
  829.     
  830.     if {$ignoreComments} {
  831.         set pat {^[\t ]*[^\t\r\n\; ]}
  832.     } else {
  833.         set pat {^[\t ]*[^\t\r\n ]}
  834.     } 
  835.     set posBeg [pos::math [lineStart $pos] - 1]
  836.     if {[pos::compare $posBeg < [minPos]]} {
  837.         set posBeg [minPos]
  838.     } 
  839.     set lwhite 0
  840.     if {![catch {search -f $direction -r 1 $pat $pos} match]} {
  841.         set posBeg [lindex $match 0]
  842.         set lwhite [posX [pos::math [lindex $match 1] - 1]]
  843.     }
  844.     set posEnd [pos::math [nextLineStart $posBeg] - 1]
  845.     if {[pos::compare $posEnd > [maxPos]]} {
  846.         set posEnd [maxPos]
  847.     } 
  848.     return [list $posBeg $lwhite [getText $posBeg $posEnd]]
  849. }
  850.  
  851. # ===========================================================================
  852. # ◊◊◊◊ Command Double Click ◊◊◊◊ #
  853. #
  854. # Checks to see if the highlighted word appears in any keyword list, and if
  855. # so, sends the selected word to the www.Lisp.com help site.
  856. # Control-Command double click will insert syntax information in status bar.
  857. # Shift-Command double click will insert commented syntax information in window.
  858. # (The above is not yet implemented -- need to enter all of the syntax info.)
  859.  
  860. proc Lisp::DblClick {from to shift option control} {
  861.     
  862.     global LispmodeVars Lispcmds LispSyntaxMessage
  863.         
  864.     select $from $to
  865.     set command [getSelect]
  866.     
  867.     set varDef "(def|make)+(\[-a-zA-Z0-9\]+(\[\t\' \]+$command)+\[\t\r\n\(\) \])"
  868.     
  869.     if {![catch {search -s -f 1 -r 1 -m 0 $varDef [minPos]} match]} {
  870.         # First check current file for a function, variable (etc)
  871.         # definition, and if found ...
  872.         placeBookmark
  873.         goto [lineStart [lindex $match 0]]
  874.         message "press <Ctl .> to return to original cursor position"
  875.         return
  876.         # Could next check any open windows, or files in the current
  877.         # window's folder ...  but not implemented.  For now, variables
  878.         # (etc) need to be defined in current file.
  879.     }
  880.     if {[lsearch -exact $Lispcmds $command] == -1} {
  881.         message "\"$command\" is not defined as a Lisp system keyword."
  882.         return
  883.     }
  884.     # Any modifiers pressed?
  885.     if {$control} {
  886.         # CONTROL -- Just put syntax message in status bar window
  887.         if {[info exists LispSyntaxMessage($command)]} {
  888.             message "$LispSyntaxMessage($command)"
  889.         } else {
  890.             message "Sorry, no syntax information available for $command"
  891.         }
  892.     } elseif {$shift} {
  893.         # SHIFT --Just insert syntax message as commented text
  894.         if {[info exists LispSyntaxMessage($command)]} {
  895.             endOfLine
  896.             insertText "\r"
  897.             insertText "$LispSyntaxMessage($command)
  898.             comment::Line
  899.         } else {
  900.             message "Sorry, no syntax information available for $command"
  901.         }
  902.     } else {
  903.         # No modifiers -- Send command for on-line help.  This is the
  904.         # "default" behavior.
  905.         message "\"$command\" sent to $LispmodeVars(lispHelp)$command"
  906.         Lisp::wwwCommandHelp $command
  907.     }
  908. }
  909.  
  910. # ===========================================================================
  911. # WWW Command Help
  912. # Send command to defined url, prompting for text if necessary.
  913.  
  914. proc Lisp::wwwCommandHelp {{command ""}} {
  915.     
  916.     global LispmodeVars
  917.     
  918.     if {$command == ""} {
  919.         set command [prompt "on-line Lisp help for ... " [getSelect]] 
  920.         # set command [statusPrompt "on-line help for ... " ] 
  921.     } 
  922.     message "\"$command\" sent to $LispmodeVars(lispHelp)"
  923.     icURL $LispmodeVars(lispHelp)$command
  924. }
  925.  
  926. # ===========================================================================
  927. #
  928. # ◊◊◊◊ Mark File and Parse Functions ◊◊◊◊ #
  929. #
  930.  
  931. # ===========================================================================
  932. #
  933. # Lisp Mark File
  934. # This will return the first 35 characters from the first non-commented word
  935. # that appears in position 0.
  936. #
  937.  
  938. proc Lisp::MarkFile {} {
  939.     
  940.     message "Marking File …"
  941.     
  942.     set count 0
  943.     set pos [minPos]
  944.     set pat {^(;;\*;;[ ]|;;;\*;;;[ ]|\()[a-zA-Z0-9]}
  945.     while {![catch {search -s -f 1 -r 1 -m 0 -i 1 $pat $pos} match]} {
  946.         incr count
  947.         set posBeg [lindex $match 0]
  948.         set posEnd [nextLineStart $posBeg]
  949.     if {[pos::compare $posEnd > [maxPos]]} {set posEnd [maxPos]}
  950.         set line  [string trimright [getText $posBeg $posEnd]]
  951.         set line  "  $line"
  952.         regsub -all "\{" $line "(" line
  953.         regsub -all "\}" $line ")" line
  954.         if {[regsub {  ;;;\*;;; } $line {* } line]} {
  955.             incr count -1
  956.         } elseif {[regsub {  ;;\*;; } $line {• } line]} {
  957.             incr count -1
  958.         } 
  959.         if {[string length $line] > 35} {
  960.             set line "[string range $line 0 35] ..."
  961.         }
  962.         setNamedMark $line $posBeg $posBeg $posBeg
  963.         set pos $posEnd
  964.     }
  965.     message "This file contains $count commands."
  966. }
  967.  
  968. # ===========================================================================
  969. #
  970. # Lisp Parse Functions
  971. # This will return only the Lisp command names.
  972.  
  973. proc Lisp::parseFuncs {} {
  974.     
  975.     global sortFuncsMenu
  976.     
  977.     set pos [minPos]
  978.     set m {}
  979.     while {[set match [search -s -f 1 -r 1 -i 0 -n {^\((\w+)} $pos]] != ""} {
  980.         if {[regexp -- {(\w+)} [eval getText $match] "" word]} {
  981.             lappend m [list $word [lindex $match 0]]
  982.         }
  983.         set pos [lindex $match 1]
  984.     }
  985.     if {$sortFuncsMenu} {
  986.         regsub -all "\[\{\}\]" [lsort -ignore $m] "" m
  987.     } else {
  988.         regsub -all "\[\{\}\]" $m "" m
  989.     }   
  990.     return  $m
  991. }
  992.  
  993. # ===========================================================================
  994. # ◊◊◊◊ -------------------- ◊◊◊◊ #
  995. # ◊◊◊◊ Lisp Menu ◊◊◊◊ #
  996.  
  997. proc lispMenu {} {}
  998.  
  999. proc Lisp::LispModeMenuItem {{Lisp 1} {Scm 1}} {
  1000.     
  1001.     global mode
  1002.     
  1003.     set kill 1
  1004.     if {$Lisp && $mode == "Lisp"} {
  1005.         set kill 0
  1006.     } 
  1007.     if {$Scm && $mode == "Scm"} {
  1008.         set kill 0
  1009.     } 
  1010.     if {$kill} {
  1011.         alertnote "You might have encountered a known key-binding bug,\
  1012.           in which case you must use the menu bar.  Otherwise, you\
  1013.           selected a menu item that is not applicable to $mode files !"
  1014.         error "Lisp proc called, but not in applicable mode."
  1015.     } 
  1016. }
  1017.  
  1018. # Tell Alpha what procedures to use to build all menus, submenus.
  1019.  
  1020. menu::buildProc lispMenu           Lisp::buildMenu
  1021. menu::buildProc lispHelp           Lisp::buildLispHelpMenu
  1022. menu::buildProc markLispFileAs…    Lisp::buildLispMarkMenu
  1023.  
  1024. # First build the main Lisp menu.
  1025.  
  1026. proc Lisp::buildMenu {} {
  1027.     
  1028.     global lispMenu
  1029.     
  1030.     set menuList [list                      \
  1031.       "lispHomePage"                        \
  1032.       "/S<U<OswitchToLisp"                  \
  1033.       "(-"                                  \
  1034.       [list Menu -n lispHelp {}]            \
  1035.       [list Menu -n markLispFileAs…    {}]  \
  1036.       "(-"                                  \
  1037.       "/P<U<OprocessFile"                   \
  1038.       "/P<U<O<BprocessSelection"            \
  1039.       "(-"                                  \
  1040.       "/b<UcontinueCommand"                 \
  1041.       "(-"                                  \
  1042.       "/N<U<BnextCommand"                   \
  1043.       "/P<U<BprevCommand"                   \
  1044.       "/S<U<BselectCommand"                 \
  1045.       "/I<B<OreformatCommand"               \
  1046.       ]
  1047.     set submenus [list lispHelp markLispFileAs… ]
  1048.     return       [list build $menuList Lisp::menuProc $submenus $lispMenu]
  1049. }
  1050.  
  1051. # Then build the "Lisp Help" submenu.
  1052.  
  1053. proc Lisp::buildLispHelpMenu {} {
  1054.     
  1055.     global LispPrefsInMenu LispmodeVars ScmmodeVars alpha::platform
  1056.     
  1057.     # Reverse the local, www key bindings depending on the value of the
  1058.     # 'Local Help" variable.
  1059.     
  1060.     set menuList "/t<OwwwCommandHelp…"
  1061.     lappend menuList "(-"
  1062.     if {${alpha::platform} == "alpha"} {
  1063.         set prefix "!√"
  1064.     } else {
  1065.         set prefix "!•"
  1066.     } 
  1067.     foreach item $LispPrefsInMenu {
  1068.         set item [lindex $item 0]
  1069.         if {[regsub {Lisp} $item {} pref] && \
  1070.           [info exists LispmodeVars($pref)] && $LispmodeVars($pref)} {
  1071.             lappend menuList "${prefix}$item"
  1072.         } elseif {[regsub {Scm} $item {} pref] && \
  1073.           [info exists ScmmodeVars($pref)] && $ScmmodeVars($pref)} {
  1074.             lappend menuList "${prefix}$item"
  1075.         } else {
  1076.             lappend menuList "$item"
  1077.         } 
  1078.     }
  1079.     lappend menuList "(-"
  1080.     lappend menuList "checkKeywords"
  1081.     lappend menuList "addNewCommands"
  1082.     lappend menuList "addNewArguments"
  1083.     lappend menuList "setLispApplication"
  1084.     lappend menuList "(-"
  1085.     lappend menuList "/t<BlispModeHelp"
  1086.     
  1087.     return [list build $menuList Lisp::helpProc {}]
  1088. }
  1089.  
  1090. # Then build the "Mark Lisp File As" submenu.
  1091.  
  1092. proc Lisp::buildLispMarkMenu {} {
  1093.     
  1094.     global LispmodeVars ScmmodeVars alpha::platform
  1095.     
  1096.     set menuList [list                  \
  1097.       "source"                          \
  1098.       "(-"                              \
  1099.       ]
  1100.     if {${alpha::platform} == "alpha"} {
  1101.         set prefix "!√"
  1102.     } else {
  1103.         set prefix "!•"
  1104.     } 
  1105.     foreach item [list "autoMarkLisp" "autoMarkScm"] {
  1106.         set item [lindex $item 0]
  1107.         if {[regsub {Lisp} $item {} pref] && \
  1108.           [info exists LispmodeVars($pref)] && $LispmodeVars($pref)} {
  1109.             lappend menuList "${prefix}$item"
  1110.         } elseif {[regsub {Scm} $item {} pref] && \
  1111.           [info exists ScmmodeVars($pref)] && $ScmmodeVars($pref)} {
  1112.             lappend menuList "${prefix}$item"
  1113.         } else {
  1114.             lappend menuList "$item"
  1115.         } 
  1116.     }
  1117.     
  1118.     return [list build $menuList Lisp::markFileProc {}]
  1119. }
  1120.  
  1121. # Now we actually build the Lisp menu.
  1122.  
  1123. menu::buildSome lispMenu
  1124.  
  1125. proc Lisp::rebuildMenu {{menuName "lispMenu"}} {menu::buildSome $menuName}
  1126.       
  1127. # Dim menu items when there are no open windows.
  1128. set menuItems {
  1129.     markLispFileAs… continueCommand
  1130.     nextCommand prevCommand selectCommand reformatCommand
  1131. }
  1132. foreach i $menuItems {
  1133.     hook::register requireOpenWindowsHook [list lispMenu $i] 1
  1134. unset menuItems 
  1135.  
  1136. # ===========================================================================
  1137. # ◊◊◊◊ Lisp menu support ◊◊◊◊ #
  1138. # We make some of these items "Lisp Mode Only", in case Scheme mode also
  1139. # uses this menu.
  1140.  
  1141. # This is the procedure called for all main menu items.
  1142.  
  1143. proc Lisp::menuProc {menuName item} {
  1144.     Lisp::$item
  1145. }
  1146.  
  1147. # Give a beta message for untested features / menu items.
  1148.  
  1149. proc Lisp::betaMessage {{kill 1}} {
  1150.     
  1151.     message "Sorry,this feature has not been fully implemented."
  1152.     if {$kill} {return -code return}
  1153. }
  1154.  
  1155. # Return the Lisp signature.
  1156.  
  1157. proc Lisp::sig {{app "Lisp"}} {
  1158.     
  1159.     global LispmodeVars
  1160.     
  1161.     set lowApp [string tolower $app]
  1162.     set capApp [string toupper $app]
  1163.     if {$LispmodeVars(${lowApp}Sig) == ""} {
  1164.         alertnote "Looking for the $capApp application ..."
  1165.         Lisp::selectApplication $lowApp
  1166.     }
  1167.     return $LispmodeVars(${lowApp}Sig)
  1168. }
  1169.  
  1170. # ===========================================================================
  1171. # Open the Lisp home page.
  1172.  
  1173. proc Lisp::lispHomePage {} {
  1174.  
  1175.     global LispmodeVars
  1176.     
  1177.     if {$LispmodeVars(lispHomePage) != ""} {
  1178.     url::execute $LispmodeVars(lispHomePage)
  1179.     } 
  1180. }
  1181.  
  1182. # ===========================================================================
  1183. # Switch to Lisp application.
  1184.  
  1185. proc Lisp::switchToLisp {} {app::launchFore [Lisp::sig]}
  1186.  
  1187. # ===========================================================================
  1188. # ◊◊◊◊   Help ◊◊◊◊ #
  1189.  
  1190. proc Lisp::helpProc {menuName item} {
  1191.  
  1192.     global LispmodeVars LispPrefsInMenu mode
  1193.     
  1194.     if {$item == "wwwCommandHelp"} {
  1195.         Lisp::LispModeMenuItem 1 1
  1196.         $mode::wwwCommandHelp
  1197.     } elseif {[lsearch -exact $LispPrefsInMenu $item] != -1} {
  1198.         Lisp::flagFlip $item
  1199.         Lisp::rebuildMenu lispHelp
  1200.     } elseif {$item == "checkKeywords"} {
  1201.         Lisp::LispModeMenuItem 1 1
  1202.         $mode::checkKeywords 
  1203.     } elseif {$item == "addNewCommands" || $item == "addNewArguments"} {
  1204.         Lisp::LispModeMenuItem 1 1
  1205.         set item [string trimleft $item "addNew"]
  1206.         $mode::addKeywords $item
  1207.     } elseif {$item == "setLispApplication"} {
  1208.         Lisp::selectApplication "Lisp"
  1209.     } elseif {$item == "lispModeHelp"} {
  1210.         package::helpFile "Lisp"
  1211.     } else {
  1212.         Lisp::$item
  1213.     } 
  1214. }
  1215.  
  1216. proc Lisp::addKeywords {{category} {keywords ""}} {
  1217.  
  1218.     Lisp::LispModeMenuItem 1 0
  1219.     
  1220.     global LispmodeVars
  1221.     
  1222.     if {$keywords == ""} {
  1223.         set keywords [prompt "Enter new Lisp mode $category:" ""]
  1224.     }
  1225.     
  1226.     # Check to see if the keyword is already defined.
  1227.     foreach keyword $keywords {
  1228.         set checkStatus [Lisp::checkKeywords $keyword 1 0]
  1229.         if {$checkStatus != 0} {
  1230.             alertnote "Sorry, \"$keyword\" is already defined\
  1231.               in the $checkStatus list."
  1232.             message "Cancelled."
  1233.             return -code return
  1234.         } 
  1235.     }
  1236.     # Keywords are all new, so add them to the appropriate mode preference.
  1237.     append LispmodeVars(add$category) " $keywords"
  1238.     set LispmodeVars(add$category) [lsort $LispmodeVars(add$category)]
  1239.     synchroniseModeVar add$category $LispmodeVars(add$category)
  1240.     Lisp::colorizeLisp
  1241.     message "\"$keywords\" added to Lisp $category preference."
  1242. }
  1243.  
  1244. proc Lisp::checkKeywords {{newKeywordList ""} {quietly 0} {noPrefs 0}} {
  1245.     
  1246.     Lisp::LispModeMenuItem 1 0
  1247.     
  1248.     global LispmodeVars
  1249.     
  1250.     global LispAccessors LispClasses LispConditionTypes 
  1251.     global LispConstantVariables LispDeclarations LispFunctions LispMacros 
  1252.     global LispRestarts LispSpecials LispStandardGenericFunctions LispSymbols
  1253.     global LispSystemClasses LispTypes LispTypeSpecifiers LispVariables
  1254.     global LispEmacsFunctions LispEmacsArguments 
  1255.     global LispUserCommands LispUserArguments
  1256.  
  1257.     set type 0
  1258.     if {$newKeywordList == ""} {
  1259.         set quietly 0
  1260.         set newKeywordList [prompt "Enter Lisp mode keywords to be checked:" ""]
  1261.     }
  1262.     # Check to see if the new keyword(s) is already defined.
  1263.     foreach newKeyword $newKeywordList {
  1264.         if {[lsearch -exact $LispAccessors $newKeyword] != "-1"} {
  1265.             set type LispAccessors
  1266.         } elseif {[lsearch -exact $LispClasses $newKeyword] != "-1"} {
  1267.             set type LispClasses
  1268.         } elseif {[lsearch -exact $LispConditionTypes $newKeyword] != "-1"} {
  1269.             set type LispConditionTypes
  1270.         } elseif {[lsearch -exact $LispConstantVariables $newKeyword] != "-1"} {
  1271.             set type LispConstantVariables
  1272.         } elseif {[lsearch -exact $LispDeclarations $newKeyword] != "-1"} {
  1273.             set type LispDeclarations
  1274.         } elseif {[lsearch -exact $LispFunctions $newKeyword] != "-1"} {
  1275.             set type LispFunctions
  1276.         } elseif {[lsearch -exact $LispMacros $newKeyword] != "-1"} {
  1277.             set type LispMacros
  1278.         } elseif {[lsearch -exact $LispRestarts $newKeyword] != "-1"} {
  1279.             set type LispRestarts
  1280.         } elseif {[lsearch -exact $LispSpecials $newKeyword] != "-1"} {
  1281.             set type LispSpecials
  1282.         } elseif {[lsearch -exact $LispStandardGenericFunctions $newKeyword] != "-1"} {
  1283.             set type LispStandardGenericFunctions
  1284.         } elseif {[lsearch -exact $LispSymbols $newKeyword] != "-1"} {
  1285.             set type LispSymbols
  1286.         } elseif {[lsearch -exact $LispSystemClasses $newKeyword] != "-1"} {
  1287.             set type LispSystemClasses
  1288.         } elseif {[lsearch -exact $LispTypes $newKeyword] != "-1"} {
  1289.             set type LispTypes
  1290.         } elseif {[lsearch -exact $LispTypeSpecifiers $newKeyword] != "-1"} {
  1291.             set type LispTypeSpecifiers
  1292.         } elseif {[lsearch -exact $LispVariables $newKeyword] != "-1"} {
  1293.             set type LispVariables
  1294.         } elseif {[lsearch -exact $LispEmacsFunctions $newKeyword] != "-1"} {
  1295.             set type LispEmacsFunctions
  1296.         } elseif {[lsearch -exact $LispEmacsArguments $newKeyword] != "-1"} {
  1297.             set type LispEmacsArguments
  1298.         } elseif {[lsearch -exact $LispUserCommands $newKeyword] != "-1"} {
  1299.             set type LispUserCommands
  1300.         } elseif {[lsearch -exact $LispUserArguments $newKeyword] != "-1"} {
  1301.             set type LispUserArguments
  1302.         } elseif {!$noPrefs && \
  1303.           [lsearch -exact $LispmodeVars(addCommands) $newKeyword] != "-1"} {
  1304.             set type LispmodeVars(addCommands)
  1305.         } elseif {!$noPrefs && \
  1306.           [lsearch -exact $LispmodeVars(addArguments) $newKeyword] != "-1"} {
  1307.             set type LispmodeVars(addArguments)
  1308.         }
  1309.         if {$quietly} {
  1310.             # When this is called from other code, it should only contain
  1311.             # one keyword to be checked, and we'll return it's type.
  1312.             return "$type"
  1313.         } elseif {!$quietly && $type == 0} {
  1314.             alertnote "\"$newKeyword\" is not currently defined\
  1315.               as a Lisp mode keyword"
  1316.         } elseif {$type != 0} {
  1317.             # This will work for any other value for "quietly", such as "2"
  1318.             alertnote "\"$newKeyword\" is currently defined as a keyword\
  1319.               in the \"$type\" list."
  1320.         } 
  1321.         set type 0
  1322.     }
  1323. }
  1324.  
  1325. # ===========================================================================
  1326. # Select Application
  1327. # Prompt the user to locate the local Lisp application.
  1328.  
  1329. proc Lisp::selectApplication {{app "Lisp"}} {
  1330.     
  1331.     global LispmodeVars
  1332.     
  1333.     set lowApp [string tolower $app]
  1334.     set capApp [string toupper $app]
  1335.     
  1336.     set newSig ""
  1337.     set newSig [dialog::askFindApp $capApp $LispmodeVars(${lowApp}Sig)]
  1338.     
  1339.     if {$newSig != ""} {
  1340.         set LispmodeVars(${lowApp}Sig) "$newSig"
  1341.         synchroniseModeVar "${lowApp}Sig" $LispmodeVars(${lowApp}Sig)
  1342.         message "The $capApp signature has been changed to \"$newSig\"."
  1343.     } else {
  1344.         message "Cancelled."
  1345.     }
  1346. }
  1347.  
  1348. # ===========================================================================
  1349. # ◊◊◊◊   Marks ◊◊◊◊ #
  1350.  
  1351. proc Lisp::markFileProc {menu item} {
  1352.     
  1353.     if {$item == "source"} {
  1354.         markFile
  1355.     } elseif {[regexp {autoMark} $item]} {
  1356.         Lisp::flagFlip $item
  1357.         Lisp::rebuildMenu markLispFileAs…
  1358.     }
  1359. }
  1360.  
  1361. # ===========================================================================
  1362. # ◊◊◊◊   Processing ◊◊◊◊ #
  1363.  
  1364. # ===========================================================================
  1365. # Process File
  1366.  
  1367. # Send entire file to Lisp for processing, adding carriage return at end
  1368. # of file if necessary.
  1369. # Optional "f" argument allows this to be called by other code, or to be 
  1370. # sent via a Tcl shell window.
  1371.  
  1372. proc Lisp::processFile {{f ""} {app "Lisp"}} {
  1373.     
  1374.     global tcl_platform
  1375.     
  1376.     set pf $tcl_platform(platform)
  1377.     if {$f != ""} {file::openAny $f}
  1378.     getWinInfo myArray
  1379.     set theLastChar [getText [pos::math [maxPos] -1] [maxPos]]
  1380.     if {$theLastChar != "\r"} {
  1381.         set myPos [getPos]
  1382.         goto [maxPos]
  1383.         insertText "\r"
  1384.         goto $myPos
  1385.         # If window not originally dirty, remind user why s/he is being
  1386.         # asked to save file.
  1387.         if {!$myArray(dirty)} {
  1388.             alertnote "Carriage return added to end of file."
  1389.         }
  1390.     }
  1391.     openAndSendFile [Lisp::sig]
  1392. }
  1393.  
  1394. # Procedure to implement transfer of selected lines to Lisp for processing.
  1395.  
  1396. # ===========================================================================
  1397. # Process Selection
  1398.  
  1399. proc Lisp::processSelection {{app "Lisp"}} {
  1400.     
  1401.     Lisp::betaMessage 
  1402.     
  1403.     global PREFS
  1404.     
  1405.     if {[isSelection]} {
  1406.         set stuffToDo [getSelect]
  1407.         if {![file exists [file join $PREFS tmp]]} {
  1408.             file mkdir [file join $PREFS tmp]
  1409.         }
  1410.         set newFile [file join $PREFS tmp temp-Lisp.lisp]
  1411.         file::writeAll $newFile $stuffToDo 1
  1412.     } else {
  1413.         beep ; message "No selection -- cancelled."
  1414.         return
  1415.     }
  1416.     app::launchBack [Lisp::sig]
  1417.     sendOpenEvent noReply [Lisp::sig] $newFile
  1418.     switchTo [Lisp::sig]
  1419. }
  1420.  
  1421. # ===========================================================================
  1422. # ◊◊◊◊   Navigation ◊◊◊◊ #
  1423.  
  1424. proc Lisp::nextCommand {{quietly 0} {toTop 0}} {
  1425.     
  1426.     Lisp::LispModeMenuItem
  1427.  
  1428.     set pos [pos::math [nextLineStart [getPos]] - 1]
  1429.     set pat {^\([a-zA-Z0-9;]}
  1430.     if {![catch {search -f 1 -r 1 $pat $pos} match]} {
  1431.         set pos [lindex $match 0]
  1432.     } else {
  1433.         set pos [maxPos]
  1434.     }
  1435.     if {!$quietly} {
  1436.         goto $pos
  1437.         if {$pos == [maxPos]} {
  1438.             message "No further commands in the file."
  1439.         } else {
  1440.             message [getText $pos [nextLineStart $pos]]
  1441.         } 
  1442.     } 
  1443.     if {$toTop} {insertToTop}
  1444.     return $pos
  1445. }
  1446.  
  1447. proc Lisp::prevCommand {{quietly 0} {toTop 0}} {
  1448.     
  1449.     Lisp::LispModeMenuItem
  1450.  
  1451.     set pos [pos::math [getPos] - 1]
  1452.     set pat {^\([a-zA-Z0-9;]}
  1453.     if {![catch {search -f 0 -r 1 $pat $pos} match]} {
  1454.         set pos [lindex $match 0]
  1455.     } else {
  1456.         set pos [minPos]
  1457.     }
  1458.     if {!$quietly} {
  1459.         goto $pos
  1460.         if {$pos == [minPos]} {
  1461.             message "No further commands in the file."
  1462.         } else {
  1463.             message [getText $pos [nextLineStart $pos]]
  1464.         } 
  1465.     } 
  1466.     if {$toTop} {insertToTop}
  1467.     return $pos
  1468. }
  1469.  
  1470. proc Lisp::searchFunc {direction} {
  1471.     
  1472.     Lisp::LispModeMenuItem
  1473.  
  1474.     if {$direction} {
  1475.         Lisp::nextCommand
  1476.     } else {
  1477.         Lisp::prevCommand
  1478.     }
  1479. }
  1480.  
  1481. proc Lisp::selectCommand {} {
  1482.     
  1483.     Lisp::LispModeMenuItem
  1484.  
  1485.     set pos    [getPos]
  1486.     set limits [Lisp::getCommand $pos]
  1487.     set posBeg [lindex $limits 0]
  1488.     set posEnd [lindex $limits 1]
  1489.     
  1490.     if {$posBeg != "-1" && $posEnd != "-1" && \
  1491.       [pos::compare $pos >= $posBeg] && [pos::compare $pos <= $posEnd]} {
  1492.         select $posBeg $posEnd
  1493.     } else {
  1494.         message "The cursor is not within a command."
  1495.         error "The cursor is not within a command."
  1496.     } 
  1497. }
  1498.  
  1499. proc Lisp::copyCommand {{quietly 0}} {
  1500.     
  1501.     Lisp::LispModeMenuItem
  1502.  
  1503.     set pos [getPos]
  1504.     if {[set posBeg [lindex [Lisp::getCommand $pos] 0]] != "-1"} {
  1505.         set posBeg [pos::math $posBeg + 1]
  1506.         goto $posBeg
  1507.         forwardWord
  1508.         set posEnd [getPos]
  1509.         if {!$quietly} {
  1510.             select $posBeg $posEnd
  1511.             copy
  1512.             message "\"[getText $posBeg $posEnd]\" copied to clipboard."
  1513.         } 
  1514.         goto $pos
  1515.         return [getText $posBeg $posEnd]
  1516.     } elseif {!$quietly} {
  1517.         message "The cursor is not within a command."
  1518.     }
  1519.     return ""
  1520. }
  1521.  
  1522. proc Lisp::reformatCommand {{pos ""}} {
  1523.     
  1524.     Lisp::LispModeMenuItem
  1525.  
  1526.     if {$pos == ""} {set pos [getPos]}
  1527.     goto $pos
  1528.     Lisp::selectCommand
  1529.     message "Reformatting …"
  1530.     ::indentRegion
  1531.     goto [pos::math [getPos] -1]
  1532.     goto [Lisp::nextCommand 1]
  1533.     message "Reformatted."
  1534. }
  1535.  
  1536. proc Lisp::getCommand {pos {backToPos 1}} {
  1537.     
  1538.     set pos1 [pos::math [nextLineStart $pos] - 1]
  1539.     set pat {^((\([a-zA-Z0-9])|\;)}
  1540.     set posBeg "-1"
  1541.     set posEnd "-1"
  1542.     if {![catch {search -f 0 -r 1 $pat $pos1} match]} {
  1543.         set posBeg [lindex $match 0]
  1544.         set pos2   [nextLineStart $posBeg]
  1545.         if {![catch {search -f 1 -r 1 $pat $pos2} match]} {
  1546.             set posEnd [lindex $match 0]
  1547.         } else {
  1548.             set posEnd [maxPos]
  1549.         } 
  1550.         # Now back up to remove empty lines.
  1551.         set posEndPrev [pos::math $posEnd - 1]
  1552.         set prevLine [getText [lineStart $posEndPrev] $posEndPrev]
  1553.         while {[regexp {^[\t ]*$} $prevLine]} {
  1554.             set posEnd [lineStart $posEndPrev]
  1555.             set posEndPrev [pos::math $posEnd - 1]
  1556.             set prevLine [getText [lineStart $posEndPrev] $posEndPrev]
  1557.         }
  1558.     } 
  1559.     return [list $posBeg $posEnd]
  1560. }
  1561.  
  1562. # ===========================================================================
  1563. # ◊◊◊◊ -------------------- ◊◊◊◊ #
  1564. # ◊◊◊◊ version history ◊◊◊◊ #
  1565. #  modified by  rev    reason
  1566. #  -------- --- ------ -----------
  1567. #  01/28/20 cbu 1.0.1  First created Lisp mode, based upon other modes found 
  1568. #                        in Alpha's distribution, by looking at the syntax of 
  1569. #                        Emacs Speaks Statistics (ESS) suite.
  1570. #  04/01/20 cbu 1.0.2  Fixed a little bug with "comment box".
  1571. #                      Added new preferences to allow the user to optionally 
  1572. #                        use $ as a Magic Character, and to enter additional 
  1573. #                        commands and arguments.
  1574. #                      Renamed mode Lisp, from lisp  
  1575. #                      Reduced the number of different user-specified colors.
  1576. #  04/08/00 cbu 1.0.3  Added "Update Colors" proc to avoid need for a restart
  1577. #  04/16/00 cbu 1.0.4  Unset obsolete preferences from earlier versions.
  1578. #                      Added "Continue Comment" and "Electric Return Over-ride".
  1579. #                      Renamed "Update Colors" to "Update Preferences".
  1580. #  04/16/00 cbu 1.1    Renamed to lispMode.tcl
  1581. #                      Added "Mark File" and "Parse Functions" procs.
  1582. #  06/22/00 cbu 1.2    "Mark File" now recognizes headings as well as commands.
  1583. #                      Completions, Completions Tutorial added.
  1584. #                      "Reload Completions", referenced by "Update Preferences".
  1585. #                      Better support for user defined keywords.
  1586. #                      Removed "Continue Comment", now global in Alpha 7.4.
  1587. #                      Added command double-click for on-line help.
  1588. #                      <shift, control>-<command> double-click syntax info.
  1589. #                        (Foundations, at least.  Ongoing project.)
  1590. #                      Lisp-Mode split off from Statistical Modes.
  1591. #  08/08/00 cbu 1.2.1  Added message if no matching ")".
  1592. #                      DblClick now looks for function, variable (etc) 
  1593. #                        definitions in current file.
  1594. #  11/05/00 cbu 1.3    Added Lisp menu.
  1595. #                      Lisp menu is fully functional for Scheme mode, too.
  1596. #                      Added "next/prevCommand", "selectCommand", and
  1597. #                        "copyCommand" procs.
  1598. #                      Added "Lisp::indentLine".
  1599. #                      Added "Lisp::reformatCommand" to menu.
  1600. #                      Added "Lisp::continueCommand" to over-ride indents. 
  1601. #                      "Lisp::reloadCompletions" is now obsolete.
  1602. #                      "Lisp::updatePreferences" is now obsolete.
  1603. #                      "Lisp::colorizeLisp" now takes care of setting all 
  1604. #                        keyword lists, including Lispcmds.
  1605. #                      Cleaned up completion procs.  This file never has to be
  1606. #                        reloaded.  (Similar cleaning up for "Lisp::DblClick").
  1607. #  11/30/00 cbu 1.4    Fix to Lisp menu, suggested by Tom Fetherston, to make
  1608. #                        sure that the menu builds even if prefs don't exist.
  1609. #  12/01/00 cbu 2.0    New url prefs handling requires 7.4b21
  1610. #                      Added "Home Page" pref, menu item.
  1611. #                      Removed  hook::register requireOpenWindowsHook from
  1612. #                        mode declaration, put it after menu build.
  1613. #   
  1614.  
  1615. # ===========================================================================
  1616. # .
  1617.